#include<iostream>
#include<memory>

class Product
{   
    public: 
        Product(){std::cout<<"Product constructor"<<std::endl;};
        ~Product(){std::cout<<"Product destructor"<<std::endl;};
        virtual void ProductInfo()const{};
};

class ProductA:public Product
{
    public: 
        ProductA(){std::cout<<"ProductA constructor"<<std::endl;};
        ~ProductA(){std::cout<<"ProductA destructor"<<std::endl;};
        void ProductInfo()const override{std::cout<<"ProductA"<<std::endl;};
};

class ProductB:public Product
{
    public: 
        ProductB(){std::cout<<"ProductB constructor"<<std::endl;};
        ~ProductB(){std::cout<<"ProductB destructor"<<std::endl;};
        void ProductInfo()const override{std::cout<<"ProductB"<<std::endl;};
};


class Factory
{
    public: 
        Factory(){std::cout<<"Factory constructor"<<std::endl;};
        virtual ~Factory(){std::cout<<"Factory destructor"<<std::endl;};
        virtual std::shared_ptr<Product> createProduct()const{};
};

class ConcreteFactoryA:public Factory
{
    public: 
        ConcreteFactoryA(){std::cout<<"ConcreteFactoryA constructor"<<std::endl;};
        ~ConcreteFactoryA(){std::cout<<"ConcreteFactoryA destructor"<<std::endl;};
        std::shared_ptr<Product> createProduct()const override
        {
            return std::make_shared<ProductA>();
        };
};

class ConcreteFactoryB:public Factory
{
    public: 
        ConcreteFactoryB(){std::cout<<"ConcreteFactoryB constructor"<<std::endl;};
        ~ConcreteFactoryB(){std::cout<<"ConcreteFactoryB destructor"<<std::endl;};
        std::shared_ptr<Product> createProduct()const override
        {
            return std::make_shared<ProductB>();
        };
};



int main(int argc, char const *argv[])
{
    //Factory *fa = new ConcreteFactoryA;

    std::shared_ptr<ConcreteFactoryA>f(new ConcreteFactoryA);
    f->createProduct()->ProductInfo();
    // fa->createProduct()->ProductInfo();

    // fa = new ConcreteFactoryB();
    // fa->createProduct()->ProductInfo();

    // delete fa;
    return 0;
}
